#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef _WIN32
#include <io.h>
#endif // _WIN32
#include "n2base.h"
#include "BLIO.h"

FILE* n2_fopen_utf8(const char* utf8_filename, const char* mode)
{
#ifdef _WIN32
    FILE * fp;
    wchar_t *utf16_filename;
    const unsigned char * pb;
    size_t blen, n, wcount;
    bool goodutf8;
    wchar_t wmode[64];

    blen= strlen(utf8_filename);
    if (blen == 0)
        return NULL;
    blen ++;
    utf16_filename = new wchar_t[blen + 2];
    pb = (const unsigned char*) utf8_filename;
    wcount = n = 0;
    goodutf8 = true;
    while ( n < blen )
    {
        if (isUTF8Style1(pb[n])) {
            utf16_filename[wcount++] = (wchar_t) UTF8ToU32CharS1(pb[n]);
            n ++;
        } else if (isUTF8Style2(pb[n], pb[n+1])) {
            utf16_filename[wcount++] = (wchar_t) UTF8ToU32CharS2(pb[n], pb[n+1]);
            n += 2;
        } else if (isUTF8Style3(pb[n], pb[n+1], pb[n+2])) {
            utf16_filename[wcount++] = (wchar_t) UTF8ToU32CharS3(pb[n], pb[n+1], pb[n+2]);
            n += 3;
        } else if (isUTF8Style4(pb[n], pb[n+1], pb[n+2], pb[n+3])) {
            unsigned dch;
            unsigned short wch;
            dch = UTF8ToU32CharS4(pb[n], pb[n+1], pb[n+2], pb[n+3]);
            wch = (unsigned short)(dch >> 10);
            wch = (wch & 0x3ff) | 0xD800;
            utf16_filename[wcount++] = wch;
            wch = (unsigned short)(dch & 0x3ff);
            wch |= 0xDC00;
            utf16_filename[wcount++] = wch;
            n += 4;
        } else if (isUTF8Style5(pb[n], pb[n+1], pb[n+2], pb[n+3], pb[n+4])) {
            utf16_filename[wcount++] = L'?';
            n += 5;
            goodutf8 = false;
        } else if (isUTF8Style6(pb[n], pb[n+1], pb[n+2], pb[n+3], pb[n+4], pb[n+5])) {
            utf16_filename[wcount++] = L'?';
            n += 6;
            goodutf8 = false;
        } else {
            utf16_filename[wcount++] = (wchar_t) pb[n];
            n ++;
            goodutf8 = false;
        }
    }

    for (n = 0; utf16_filename[n] ; n++)
        if (utf16_filename[n] == L'/')
            utf16_filename[n] = L'\\';

    wmode[sizeof(wmode)/sizeof(wchar_t)-1] = 0;
    for (n = 0; n < sizeof(wmode)/sizeof(wchar_t)-1; n++) {
        wmode[n] = mode[n];
        if ( ! mode[n] )
            break;
    }

    if (goodutf8)
        fp = _wfopen(utf16_filename, wmode);
    else {
        fp = fopen(utf8_filename, mode);
    }

    delete[] utf16_filename;

    return fp;

#else

#endif
}

int n2_getfile_length_and_time(const char* utf8_filename, n2ulong_t * pLength, n2ulong_t* pTime)
{
    int r;
#ifdef _WIN32
    wchar_t *utf16_filename;
    const unsigned char * pb;
    size_t blen, n, wcount;
    bool goodutf8;

    blen= strlen(utf8_filename);
    if (blen == 0)
        return -1;
    blen ++;
    utf16_filename = new wchar_t[blen + 2];
    pb = (const unsigned char*) utf8_filename;
    wcount = n = 0;
    goodutf8 = true;
    while ( n < blen )
    {
        if (isUTF8Style1(pb[n])) {
            utf16_filename[wcount++] = (wchar_t) UTF8ToU32CharS1(pb[n]);
            n ++;
        } else if (isUTF8Style2(pb[n], pb[n+1])) {
            utf16_filename[wcount++] = (wchar_t) UTF8ToU32CharS2(pb[n], pb[n+1]);
            n += 2;
        } else if (isUTF8Style3(pb[n], pb[n+1], pb[n+2])) {
            utf16_filename[wcount++] = (wchar_t) UTF8ToU32CharS3(pb[n], pb[n+1], pb[n+2]);
            n += 3;
        } else if (isUTF8Style4(pb[n], pb[n+1], pb[n+2], pb[n+3])) {
            unsigned dch;
            unsigned short wch;
            dch = UTF8ToU32CharS4(pb[n], pb[n+1], pb[n+2], pb[n+3]);
            wch = (unsigned short)(dch >> 10);
            wch = (wch & 0x3ff) | 0xD800;
            utf16_filename[wcount++] = wch;
            wch = (unsigned short)(dch & 0x3ff);
            wch |= 0xDC00;
            utf16_filename[wcount++] = wch;
            n += 4;
        } else if (isUTF8Style5(pb[n], pb[n+1], pb[n+2], pb[n+3], pb[n+4])) {
            utf16_filename[wcount++] = L'?';
            n += 5;
            goodutf8 = false;
        } else if (isUTF8Style6(pb[n], pb[n+1], pb[n+2], pb[n+3], pb[n+4], pb[n+5])) {
            utf16_filename[wcount++] = L'?';
            n += 6;
            goodutf8 = false;
        } else {
            utf16_filename[wcount++] = (wchar_t) pb[n];
            n ++;
            goodutf8 = false;
        }
    }

    for (n = 0; utf16_filename[n] ; n++)
        if (utf16_filename[n] == L'/')
            utf16_filename[n] = L'\\';

    struct __stat64 st;
    if (goodutf8) {
        r = _wstat64(utf16_filename, &st);
    }
    else {
        r = _stat64(utf8_filename, &st);
    }

    delete[] utf16_filename;

    if (r == 0) {
        if (pLength)
            *pLength = st.st_size;
        if (pTime)
            *pTime = st.st_mtime;
    }
    else {
        if (pLength)
            *pLength = 0;
        if (pTime)
            *pTime = 0;
    }

    return r;

#else

#endif
}

n2long_t n2_getfilelength(FILE* fp)
{
#ifdef _WIN32
    return _filelengthi64(_fileno(fp));
#else
#endif
}




